﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Web;
using Sausage.Common;
using Sausage.Web.Code;
using Sausage.Web.DataModel;
using Sausage.Web.Models;
using Telerik.Web.Mvc;

namespace Sausage.Web.Domain
{
    public class ProjectJournalHelper
    {
        public static GridModel<object> Select(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);

            using (var context = new SausageEntities())
            {
                return
                    QueryProjectJournal(
                        context.ProjectJournal.Where(
                            item =>
                            organization.Contains(item.OrganizationID)
                            && item.State == (int)ProjectDataStateEnum.Confirmed),
                        query, isWithChild);
            }
        }

        public static GridModel<object> SubmitSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);

            using (var context = new SausageEntities())
            {
                return
                    QueryProjectJournal(
                        context.ProjectJournal.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)ProjectDataStateEnum.Unsubmit ||
                             item.State == (int)ProjectDataStateEnum.AuditRejected)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> AuditSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);

            using (var context = new SausageEntities())
            {
                return
                    QueryProjectJournal(context.ProjectJournal.Where(item =>
                    organization.Contains(item.OrganizationID) &&
                    (item.State == (int)ProjectDataStateEnum.Submitted ||
                     item.State == (int)ProjectDataStateEnum.SignRejected))
                    , query, isWithChild);
            }
        }

        public static GridModel<object> SignSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);

            using (var context = new SausageEntities())
            {
                return
                    QueryProjectJournal(context.ProjectJournal.Where(item =>
                    organization.Contains(item.OrganizationID) &&
                    (item.State == (int)ProjectDataStateEnum.Audited ||
                     item.State == (int)ProjectDataStateEnum.ConfirmationRejected))
                    , query, isWithChild);
            }
        }

        public static GridModel<object> ConfirmSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);

            using (var context = new SausageEntities())
            {
                return
                    QueryProjectJournal(context.ProjectJournal.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)ProjectDataStateEnum.Signed)
                    , query, isWithChild);
            }
        }

        private static GridModel<object> QueryProjectJournal(IQueryable<ProjectJournal> source, JosnPagingQueryModel query, bool isWithChild)
        {
            var result = UIHelper.GetGridModelFromQueryModel<ProjectJournal>(
                source,
                query.page,
                query.limit,
                GetSortDescriptorFromQueryModel(query.SortModel),
                GetSearchFilterFromQueryModel(query.FilterModel, isWithChild));

            var list = result.Data.Select(item => new
            {
                item.JournalID,
                item.OrganizationID,
                Organization = item.Organization.OrganizationName,
                item.ProjectID,
                ProjectCode = item.Project.ProjectCode,
                ProjectName = item.Project.ProjectName,
                item.Weather,
                item.Content,
                item.CreateDate,
                item.Applicant,
                item.ApplicationDate,
                item.Auditor,
                item.AuditedDate,
                item.Signer,
                item.SignedDate,
                item.Approver,
                item.ApprovedDate,
                item.State,
                item.IsDelay,
                item.Memo,
                item.Comment
            }).ToList();

            return new GridModel<object>()
            {
                Aggregates = result.Aggregates,
                Data = list,
                Total = result.Total
            };
        }

        private static List<IFilterDescriptor> GetSearchFilterFromQueryModel(IEnumerable<JosnQueryFilterModel> filterModels, bool isWithChild)
        {
            var filterList = new List<IFilterDescriptor>();
            foreach (var item in filterModels)
            {
                if (string.IsNullOrEmpty(item.value))
                    continue;
                
                if (item.property == "OrganizationID" && isWithChild)
                    continue;

                if (item.property.EndsWith("ID", StringComparison.InvariantCultureIgnoreCase))
                {
                    var targetID = Guid.Parse(item.value);
                    if (targetID != Guid.Empty)
                        filterList.Add(new FilterDescriptor(item.property, FilterOperator.IsEqualTo, targetID));
                }
                else if (item.property == "ApplicationDate_L") //startData - begin
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "ApplicationDate_H") // startDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else if (item.property == "SignedDate_L") // signedDate - begin.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("SignedDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "SignedDate_H") // signedDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("SignedDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else //other filter.
                    filterList.Add(new FilterDescriptor(item.property, FilterOperator.Contains, item.value));
            }
            return filterList;
        }

        private static List<SortDescriptor> GetSortDescriptorFromQueryModel(IEnumerable<JosnQuerySortModel> sortModels)
        {
            //convert the sort description.
            var sortList = new List<SortDescriptor>();
            foreach (var item in sortModels)
            {
                var descriptor = new SortDescriptor()
                {
                    Member = item.property,
                    SortDirection =
                        item.direction.ToLower() == "desc"
                            ? ListSortDirection.Descending
                            : ListSortDirection.Ascending
                };

                if (descriptor.Member == "Organization")
                    descriptor.Member = "Organization.OrganizationName";
                else if (descriptor.Member == "ProjectName")
                    descriptor.Member = "Project.ProjectName";
                else if (descriptor.Member == "ProjectCode")
                    descriptor.Member = "Project.ProjectCode";

                sortList.Add(descriptor);
            }
            return sortList;
        }

        public static ProjectJournal GetProjectJournalByID(Guid id)
        {
            using (SausageEntities context = new SausageEntities())
            {
                return context.ProjectJournal.Include("Organization").Include("Project").Include("ProjectPhoto").FirstOrDefault(
                        projectJournal => projectJournal.JournalID == id);
            }
        }

        public static void DeleteProjectJournal(Guid id)
        {
            using (SausageEntities context = new SausageEntities())
            {
                var projectJournal = new ProjectJournal();
                projectJournal.JournalID = id;

                var projectPhotoList = context.ProjectPhoto.Where(item => item.JournalID == id).ToList();
                var sourceFolder = HttpContext.Current.Server.MapPath(Utility.ProjectJournalFolder);
                foreach (var projectPhoto in projectPhotoList)
                {
                    context.CreateObjectSet<ProjectPhoto>().Attach(projectPhoto);
                    try
                    {
                        string sourcePath = string.Concat(sourceFolder,
                                                          Path.DirectorySeparatorChar, projectPhoto.PhotoID,
                                                          projectPhoto.FileExtension);
                        if (File.Exists(sourcePath))
                            File.Delete(sourcePath);
                    }
                    catch {/*do nothing*/}
                    context.ObjectStateManager.ChangeObjectState(projectPhoto, EntityState.Deleted);
                }

                context.CreateObjectSet<ProjectJournal>().Attach(projectJournal);
                context.ObjectStateManager.ChangeObjectState(projectJournal, EntityState.Deleted);
                context.SaveChanges();
            }
        }

        public static Guid CreateProjectJournal(ProjectJournalListRow data)
        {
            Guid journalID = Guid.NewGuid();

            using (var context = new SausageEntities())
            {
                var entity = new ProjectJournal();
                entity.JournalID = journalID;
                entity.ProjectID = data.ProjectID;
                entity.OrganizationID = Helper.CurrentPrincipal.Organization.OrganizationID;
                entity.Weather = data.Weather;
                entity.Content = data.Content;
                entity.CreateDate = DateTime.Now;
                entity.Applicant = Helper.CurrentPrincipal.User.UserName;
                entity.ApplicationDate = data.ApplicationDate;
                entity.Memo = data.Memo;
                entity.IsDelay = Helper.IsDelay(data.ApplicationDate);
                entity.State = (int)ProjectDataStateEnum.Unsubmit;

                context.ProjectJournal.AddObject(entity);
                context.SaveChanges();
            }

            if (data.Photos != null && data.Photos.Length > 0)
                FileUploadHelper.MoveFileFromTempToProjectPhoto(journalID, data.Photos);

            return journalID;
        }

        public static void UpdateProjectJournal(ProjectJournalListRow data)
        {
            using (var context = new SausageEntities())
            {
                var entity = context.ProjectJournal.FirstOrDefault(item => item.JournalID == data.JournalID);
                if (entity == null)
                    return;

                if (entity.State != (int)ProjectDataStateEnum.Unsubmit && entity.State != (int)ProjectDataStateEnum.AuditRejected)
                    throw new SausageException(string.Format("项目工程日志已经提交，不允许执行编辑操作。"));

                entity.ProjectID = data.ProjectID;
                entity.Weather = data.Weather;
                entity.Content = data.Content;
                entity.Applicant = Helper.CurrentPrincipal.User.UserName;
                //entity.ApplicationDate = data.ApplicationDate;
                entity.Memo = data.Memo;

                context.SaveChanges();
            }
        }

        public static bool DeleteProjectJournalPhoto(Guid photoID)
        {
            using (var context = new SausageEntities())
            {
                var photoList = context.ProjectPhoto.Where(item => item.PhotoID == photoID).ToList();
                if (photoList == null || photoList.Count <= 0)
                    return true;

                foreach (var projectPhoto in photoList)
                {
                    string filePath = string.Concat(HttpContext.Current.Server.MapPath(Utility.ProjectJournalFolder),
                                                    Path.DirectorySeparatorChar, projectPhoto.PhotoID,
                                                    projectPhoto.FileExtension);
                    try
                    {
                        if (File.Exists(filePath))
                            File.Delete(filePath);

                        context.DeleteObject(projectPhoto);
                        context.SaveChanges();
                    }
                    catch
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public static List<object> GetJournalPhotos(Guid journalID)
        {
            using (SausageEntities context = new SausageEntities())
            {

                var list = context.ProjectPhoto.Where(item => item.JournalID == journalID).ToList();
                return list.Select(item => new
                {
                    PhotoID = item.PhotoID,
                    JournalID = item.JournalID,
                    PhotoName = item.PhotoName,
                    FileExtension = item.FileExtension,
                    Url = (new System.Web.Mvc.UrlHelper(HttpContext.Current.Request.RequestContext)).Action("Photo", "ProjectJournal", new { photoID = item.PhotoID }),
                    Memo = item.Memo
                }).ToList<object>();
            }
        }

        public static void ExecuteSubmit(Guid[] journals)
        {
            if (null != journals && journals.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectJournal.Where(item => journals.Contains(item.JournalID)).ToList();

                    foreach (var entity in list)
                    {
                        entity.State = (int)ProjectDataStateEnum.Submitted;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteAudit(Guid[] journals, bool passed, string comment)
        {
            if (null != journals && journals.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectJournal.Where(item => journals.Contains(item.JournalID)).ToList();

                    foreach (var target in list)
                    {
                        target.Auditor = Helper.CurrentPrincipal.User.UserName;
                        target.AuditedDate = DateTime.Now;
                        target.Comment = comment;
                        target.State = passed
                                                     ? (int)ProjectDataStateEnum.Audited
                                                     : (int)ProjectDataStateEnum.AuditRejected;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteConfirm(Guid[] journals, bool passed, string comment)
        {
            if (null != journals && journals.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectJournal.Where(item => journals.Contains(item.JournalID)).ToList();

                    foreach (var target in list)
                    {
                        target.Approver = Helper.CurrentPrincipal.User.UserName;
                        target.ApprovedDate = DateTime.Now;
                        target.Comment = comment;
                        target.State = passed
                                                     ? (int)ProjectDataStateEnum.Confirmed
                                                     : (int)ProjectDataStateEnum.ConfirmationRejected;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteSign(Guid[] journals, bool passed)
        {
            if (null != journals && journals.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.ProjectJournal.Where(item => journals.Contains(item.JournalID)).ToList();

                    foreach (var target in list)
                    {
                        target.Signer = Helper.CurrentPrincipal.User.UserName;
                        target.SignedDate = DateTime.Now;
                        target.State = passed
                                                     ? (int)ProjectDataStateEnum.Signed
                                                     : (int)ProjectDataStateEnum.SignRejected;
                    }
                    context.SaveChanges();
                }
            }
        }


        public static ProjectPhoto GetPhoto(Guid photoID)
        {
            using (SausageEntities context = new SausageEntities())
            {
                return context.ProjectPhoto.FirstOrDefault(item => item.PhotoID == photoID);
            }
        }
    }
}